package cn.iocoder.an.module.mold.job;


import cn.iocoder.an.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.an.framework.quartz.core.handler.JobHandler;
import cn.iocoder.an.framework.tenant.core.job.TenantJob;
import cn.iocoder.an.module.business.dal.dataobject.warningconfig.WarningConfigDO;
import cn.iocoder.an.module.business.dal.mysql.warningconfig.WarningConfigMapper;
import cn.iocoder.an.module.business.utils.WeComMessageUtil;
import cn.iocoder.an.module.mold.controller.admin.upkeeptobe.vo.UpkeepTobeSaveReqVO;
import cn.iocoder.an.module.mold.dal.dataobject.account.AccountDO;
import cn.iocoder.an.module.mold.dal.dataobject.upkeepcategory.UpkeepCategoryDO;
import cn.iocoder.an.module.mold.dal.dataobject.upkeeptobe.UpkeepTobeDO;
import cn.iocoder.an.module.mold.dal.mysql.upkeeptobe.UpkeepTobeMapper;
import cn.iocoder.an.module.mold.service.account.AccountService;
import cn.iocoder.an.module.mold.service.upkeepcategory.UpkeepCategoryService;
import cn.iocoder.an.module.mold.service.upkeeptobe.UpkeepTobeService;
import cn.iocoder.an.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.an.module.system.service.dict.DictDataService;
import cn.iocoder.an.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DateUtil.now;

@Component
public class autoCreateUpkeepTobeJob implements JobHandler {

    @Resource
    private AccountService accountService;

    @Resource
    private UpkeepCategoryService upkeepCategoryService;

    @Resource
    private AdminUserService userService;

    @Autowired
    private WeComMessageUtil weComMessageUtil;

    @Resource
    private UpkeepTobeService UpkeepTobeService;

    @Resource
    private UpkeepTobeMapper UpkeepTobeMapper;

    @Resource
    private WarningConfigMapper warningConfigMapper;

    @Resource
    private DictDataService dictDataService;

    @Override
    @TenantJob // 标记多租户
    public String execute(String param) throws Exception {
        //保养任务自动预警以及生成
        System.out.println("自动生成待保养计划任务开始");
        LocalDate now = LocalDate.now();
        //思路：自动生成待保养任务
        // 1,查询所有的保养类型, 然后生成ID到对应类型实体的一个map
        List<UpkeepCategoryDO> upkeepCategoryDOList = upkeepCategoryService.getUpkeepCategoryAll();
        if (CollectionUtils.isEmpty(upkeepCategoryDOList)) {
            return "无保养类型";
        }
        Map<Long, UpkeepCategoryDO> upkeepCategoryDOMap = upkeepCategoryDOList.stream().collect(
                Collectors.toMap(UpkeepCategoryDO::getId, upkeepCategoryDO -> upkeepCategoryDO));

        //2 暴力做法: 查询所有的模具列,
        List<AccountDO> accounts = accountService.getAccountAll();

        accounts.forEach(accountDO -> {
            Long upkeepId = accountDO.getUpkeepId();
            UpkeepCategoryDO upkeepCategoryDO = upkeepCategoryDOMap.get(upkeepId);
            if (upkeepCategoryDO == null) {
                return;
            }
            Long tobePeriod = upkeepCategoryDO.getTobePeriod();
            if (tobePeriod == null || tobePeriod <= 0) {
                return;
            }

            //实际下次保养日期，实时运算
            LocalDateTime nextUpkeepTime = accountDO.getLastUpkeepTime().plusDays(upkeepCategoryDO.getUpkeepPeriod());
            if (nextUpkeepTime == null) {
                return;
            }
            //下次保养日期与当前日期差
            long between = ChronoUnit.DAYS.between(now, nextUpkeepTime);

            //小于制单周期，生成待保养任务
            if (between <= tobePeriod) {
                UpkeepTobeSaveReqVO createReqVO = new UpkeepTobeSaveReqVO(
                );
                createReqVO.setAccountId(accountDO.getId());
                createReqVO.setUpkeepId(upkeepId);
                createReqVO.setLastUpkeepTime(accountDO.getLastUpkeepTime());
                createReqVO.setIfTmp(0);
                UpkeepTobeService.createUpkeepTobe(createReqVO);
            }
     /*       System.out.println();
            //控制台打印出 保养周期 上次保养日期 下次保养周期   制单周期  是否制单
            System.out.println("保养周期："+upkeepCategoryDO.getUpkeepPeriod() + ";距离下次保养日期:" + between  + ";上次保养日期:" + accountDO.getLastUpkeepTime() +  ";  下次保养日期:" + nextUpkeepTime + ";  制单周期:" + tobePeriod + "  " + "是否制单:" + Boolean.toString(between <= tobePeriod));
    */
        });

        //自动通过预警配置中的配置项进行提醒
        //1.先获取预警配置项 按照预警天数从小到大排序
        LambdaQueryWrapperX<WarningConfigDO> configWrapper = new LambdaQueryWrapperX<>();
        configWrapper.eq(WarningConfigDO::getWarningType, 4);
        configWrapper.orderByAsc(WarningConfigDO::getWarningDays);
        List<WarningConfigDO> configList = warningConfigMapper.selectList(configWrapper);

        //这里直接去查询待保养任务，然后进行提醒
        LambdaQueryWrapperX<UpkeepTobeDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(UpkeepTobeDO::getStatus, 1).eq(UpkeepTobeDO::getDeleted, 0);
        List<UpkeepTobeDO> tobes = UpkeepTobeMapper.selectList(queryWrapper);

        tobes.forEach(upkeepTobeDO -> {
            UpkeepCategoryDO upkeepCategoryDO = upkeepCategoryDOMap.get(upkeepTobeDO.getUpkeepId());
            if (upkeepCategoryDO == null) {
                return;
            }
            Long upkeepPeriod = upkeepCategoryDO.getUpkeepPeriod();
            //保养周期
            if (upkeepPeriod == null || upkeepPeriod <= 0) {
                return;
            }
            //3: 校验保养时间以及提醒时间: 下次保养时间减去当前时间 是否满足 小于提醒日期且大于0
            configList.forEach(warningConfigDO -> {
                if (upkeepTobeDO.getLastUpkeepTime() == null) {
                    return;
                }

                // 实时计算时间差： 保养周期 -(当前日期-上次保养日期)
                long between = ChronoUnit.DAYS.between(LocalDate.now(), upkeepTobeDO.getLastUpkeepTime());
                //时间差大于保养周期，发送提醒
                if ((upkeepPeriod - between) == warningConfigDO.getWarningDays()) {
                    AccountDO accountDO = accountService.getAccount(upkeepTobeDO.getAccountId());
                    LocalDateTime nextUpkeepTime = accountDO.getLastUpkeepTime().plusDays(upkeepCategoryDO.getUpkeepPeriod());
                    sendKeepMessage(warningConfigDO.getWarningUser(), accountDO, nextUpkeepTime);
                    //打印account的编码、上次保养时间，warningConfigDO的预警日期， upkeepCategoryDO的保养周期；时间差，下次保养时间
                    System.out.println();
                    System.out.println("编码：" + accountDO.getCode() + ";上次保养时间:" + upkeepTobeDO.getLastUpkeepTime() + ";  预警配置的时间" + warningConfigDO.getWarningDays() + ";  保养周期:" + upkeepPeriod + ";  时间差:" + between + ";  下次保养时间:" + nextUpkeepTime);
                    return;
                }
                //打印当前日期，保养周期，时间差，上次保养日期

            });
        });

        return null;
    }

    public void sendKeepMessage(List<Long> dutyUserId, AccountDO account, LocalDateTime nextCheckTime) {
        //推送消息
        List<AdminUserDO> userList = userService.getUserList(dutyUserId);
        String userIds = "";
        StringBuilder userIdBuilder = new StringBuilder();
        // 获取当前时间并格式化
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter formattertime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedNow = nextCheckTime.format(formatter);
        for (AdminUserDO user : userList) {
            String userId = weComMessageUtil.getUserIdByMobile(user.getEnterpriseWeChatAccount());
            if (userId != null && !userId.trim().isEmpty()) {
                // 如果已经有内容了，先添加分隔符
                if (userIdBuilder.length() > 0) {
                    userIdBuilder.append("|");
                }
                userIdBuilder.append(userId);
            }
        }

        userIds = userIdBuilder.toString();
        if (userIds.isEmpty()) {
            System.out.printf("没有找到任何有效的企业微信 UserID");
            return;
        }
        // 1. 使用 sendTextMessage 方法 (更灵活，可以同时指定用户、部门、标签)
        String text = "模具保养预警通知：您有新的模具待保养，模具编号如下：【" + account.getCode() + "】，计划保养时间时间为：" + formattedNow + "请在规划时间完成模具保养工作。";
        String systemMessage = text + LocalDateTime.now().format(formattertime);
        WeComMessageUtil.WeComSendResult weComSendResult = weComMessageUtil.sendTextMessage(systemMessage, userIds, null, null);
        System.out.printf("推送结果:" + weComSendResult.toString());
    }
}
